package br.rfpm.dominio;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.springframework.security.core.Authentication;

@Entity
@Table(catalog = "condominio", name = "usuario")
public class Usuario implements Authentication {

	private static final long serialVersionUID = -1136121327246336603L;

	public static Boolean AUTHENTICATED = true;

	@Id
	@GenericGenerator(name = "increment-strategy", strategy = "increment", parameters = { @Parameter(name = "schema", value = "condominio") })
	@GeneratedValue(generator = "increment-strategy", strategy = GenerationType.TABLE)
	@Column(name = "ID_USUARIO")
	private Long id;

	@Column(name = "LOGIN")
	private String login;

	@Column(name = "NOME")
	private String name;

	@Column(name = "CREDENTIALS")
	private String credentials;

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinTable(name = "USUARIO_AUTHORITY", joinColumns = { @JoinColumn(name = "ID_USUARIO") }, inverseJoinColumns = { @JoinColumn(name = "ID_AUTHORITY") })
	private List<Authority> authorities;

	@Transient
	private Boolean authenticated = false;

	public Usuario() {

	}

	public Usuario(String login) {
		this.login = login;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getLogin() {
		return this.login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	@Override
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public List<Authority> getAuthorities() {
		return this.authorities;
	}

	public void setAuthorities(List<Authority> authorities) {
		this.authorities = authorities;
	}

	@Override
	public Object getCredentials() {
		return this.credentials;
	}

	public void setCredentials(String credentials) {
		this.credentials = credentials;
	}

	@Override
	public Object getDetails() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object getPrincipal() {
		return this;
	}

	@Override
	public boolean isAuthenticated() {
		return this.authenticated;
	}

	public Boolean getAuthenticated() {
		return authenticated;
	}

	@Override
	public void setAuthenticated(boolean authenticated)
			throws IllegalArgumentException {
		this.authenticated = authenticated;
	}

	/**
	 * Adiciona uma permissao(GrantedAuthority) ao usuario e adiciona tambem a
	 * permissao de ROLE_USER caso o usuario ainda nao possua
	 * 
	 * @param authority
	 * @throws DominioException
	 */
	public void addAuthority(Authority authority) throws DominioException {
		if (this.authorities == null) {
			this.authorities = new ArrayList<Authority>();
		}
		if (!this.authorities.contains(authority)) {
			this.authorities.add(authority);
		} else {
			throw new DominioException("Usuário ja possui a permissão: "
					+ authority.getAuthority());
		}
	}

	/**
	 * Adiciona um conjunto de permissoes(List<GrantedAuthority>) ao usuario
	 * 
	 * @param authorities
	 * @throws DominioException
	 */
	public void addAllAuthority(List<Authority> authorities)
			throws DominioException {
		List<String> repeatedAuthorities = new ArrayList<String>();
		for (Authority authority : authorities) {
			if (!this.authorities.contains(authority)) {
				this.addAuthority(authority);
			} else {
				repeatedAuthorities.add(authority.getAuthority());
			}
		}

		if (!repeatedAuthorities.isEmpty()) {
			throw new DominioException("Usuário ja possui permissão de: "
					+ repeatedAuthorities);
		}

	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((authenticated == null) ? 0 : authenticated.hashCode());
		result = prime * result
				+ ((authorities == null) ? 0 : authorities.hashCode());
		result = prime * result
				+ ((credentials == null) ? 0 : credentials.hashCode());
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((login == null) ? 0 : login.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Usuario other = (Usuario) obj;
		if (authenticated == null) {
			if (other.authenticated != null)
				return false;
		} else if (!authenticated.equals(other.authenticated))
			return false;
		if (authorities == null) {
			if (other.authorities != null)
				return false;
		} else if (!authorities.equals(other.authorities))
			return false;
		if (credentials == null) {
			if (other.credentials != null)
				return false;
		} else if (!credentials.equals(other.credentials))
			return false;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (login == null) {
			if (other.login != null)
				return false;
		} else if (!login.equals(other.login))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Usuario [id=" + id + ", login=" + login + ", name=" + name
				+ ", credentials=" + credentials + ", authorities="
				+ authorities + ", authenticated=" + authenticated + "]";
	}

}
